package RabbiMQ

import (
	"fmt"
	"github.com/streadway/amqp"
	"log"
)

//定义mq的连接,格式是固定的，amqp://账号:密码@rabbitmq服务器地址:端口号:vhost
const MQURL = "amqp://admin:123456@134.175.35.103:5672/imoc"

//创建一个结构体。方便调用.写小写,是不让别人调用,Go的概念。
type RabbitMQ struct {
	conn    *amqp.Connection
	channel *amqp.Channel
	//队列名称
	QueueName string
	// 交换机
	Exchange string
	// key
	Key string
	// 连接信息
	Mqurl string
}

//创建RabbitMQ结构体的实例
func NewRabbitMQ(queueName string, exchange string, key string) *RabbitMQ {
	rabbitmq := &RabbitMQ{
		QueueName: queueName,
		Exchange:  exchange,
		Key:       key,
		Mqurl:     MQURL}
	var err error
	rabbitmq.conn, err = amqp.Dial(rabbitmq.Mqurl)
	rabbitmq.failOnErr(err, "创建连接错误!")
	rabbitmq.channel, err = rabbitmq.conn.Channel()
	rabbitmq.failOnErr(err, "获取channel失败")
	return rabbitmq
}

//创建函数断开连接
func (r *RabbitMQ) Destory() {
	r.channel.Close()
	r.conn.Close()
}

//创建函数,处理错误.
func (r *RabbitMQ) failOnErr(err error, message string) {
	if err != nil {
		log.Fatalf("%s%S", message, err)
		panic(fmt.Sprintf("%s:%s", message, err))
	}
}

//1. 创建简单模式RabbitMQ实例
func NewRabbitMQSimple(queueName string) *RabbitMQ {
	return NewRabbitMQ(queueName, "", "")

}

// 2. 创建艰简单模式Step: 2.简单模式下生产代码
func (r *RabbitMQ) PublishSimple(message string) {
	//1.消息队列,如果队列不存在会自动创建，如果存在则跳过创建
	//保证队列存在，消息队列存在队列中
	_, err := r.channel.QueueDeclare(
		r.QueueName,
		//是否持久化
		false,
		// 是否维自动删除
		false,
		//是否具有排他性
		false,
		//是否阻塞
		false,
		//额外属性
		nil,
	)
	if err != nil {
		fmt.Println(err)
	}
	//2.发送消息队列中
	r.channel.Publish(
		r.Exchange,
		r.QueueName,
		//如果为true,根据exhange类型和routkey规则，如果无法找到和条件的队列那么会把发送的消息发送给发送者
		false,
		//如果为true,当exchange发送消息队列上没有绑定，会把消息退回。
		false,
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		})
}
func (r *RabbitMQ) ConsumeSimple() {
	// 1.申请队列，如果队列，不存在就会创建，如果存在则跳过创建
	// 保持队列存在，消息能发送到队列中
	_, err := r.channel.QueueDeclare(
		r.QueueName,
		//是否持久化
		false,
		// 是否维自动删除
		false,
		//是否具有排他性
		false,
		//是否阻塞
		false,
		//额外属性
		nil,
	)
	if err != nil {
		fmt.Println(err)
	}
	//2. 接受消息
	msgs, err := r.channel.Consume(
		r.QueueName,
		//用来区分多个消费着
		"",
		//是否自动应答
		true,
		//是否有排他性
		false,
		//如果设置为true,不能将同一个connection中发送的消息传递给这个connection中的消费者
		false,
		// 队列消费是否阻塞false是阻塞。
		false,
		nil)
	if err != nil {
		fmt.Println(err)
	}
	//创建一个变量
	forever := make(chan bool)
	//启动协程处理消息
	go func() {
		for d := range msgs {
			//实现我们要处理的函数
			log.Printf("处理的函数:%s", d.Body)
			fmt.Println(d.Body)
		}
	}()
	log.Printf("接受等待消息")
	<-forever
}
